/*
 * MIDPDisplay.java
 *
 * Created on 2005/02/28 +0900
 *
 * $Revision: 42 $
 * $Date: 2008-10-26 14:12:53 +0000 (Sun, 26 Oct 2008) $
 */

package org.gikolet.framework.platform.midp.internal;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;

import org.gikolet.framework.application.ApplicationLifecycle;
import org.gikolet.framework.inject.Injector;
import org.gikolet.framework.inject.Serviceable;
import org.gikolet.framework.ui.CancelException;
import org.gikolet.framework.ui.Display;
import org.gikolet.framework.ui.Font;
import org.gikolet.framework.ui.FontProvider;
import org.gikolet.framework.ui.MenuItem;
import org.gikolet.framework.ui.events.KeyEvent;
import org.gikolet.framework.util.Assert;

/**
 * @author Tetsutaro (latest modification by $Author: tetsutaro.ss $)
 * @version $Revision: 42 $ $Date: 2008-10-26 14:12:53 +0000 (Sun, 26 Oct 2008) $
 */
public class MIDPDisplay extends Display implements Serviceable, ApplicationLifecycle {
    private Injector injector;

    private MIDPFontProvider midpFontProvider;

    private Displayable current;
    private MWTCanvas canvas;
    private TextBox textBox;

    private Command menuCmd;
    private Command popMenuCmd;

    private Command inputOkCmd;
    private Command inputCancelCmd;

    public MIDPDisplay() {
	super();

	this.canvas = new MWTCanvas();
	this.textBox = new TextBox("", "", Short.MAX_VALUE, TextField.ANY);

	this.menuCmd = new Command("MENU", Command.SCREEN, 0);
	this.popMenuCmd = new Command("MENU", Command.SCREEN, 1);

	this.inputOkCmd = new Command("OK", Command.SCREEN, 0);
	this.inputCancelCmd = new Command("CANCEL", Command.SCREEN, 1);

	CommandListener listener = new CommandListener() {
	    public void commandAction(Command c, Displayable d) {
		MIDPDisplay.this.commandAction(c, d);
	    }
	};

	this.canvas.setCommandListener(listener);
	this.textBox.setCommandListener(listener);
	this.textBox.addCommand(this.inputOkCmd);
	this.textBox.addCommand(this.inputCancelCmd);

	this.midpFontProvider = new MIDPFontProvider();

	javax.microedition.lcdui.Font midpFont = javax.microedition.lcdui.Font
		.getDefaultFont();

	this.midpFontProvider.setDefaultNativeFont(midpFont);
    }

    public void service(Injector injector) {
	this.injector = injector;
    }

    private MIDlet getMIDlet() {
	Assert.isNotNull(this.injector);
	return (MIDlet) this.injector.getInstance(MIDlet.class);
    }

    public FontProvider getFontProvider() {
	return this.midpFontProvider;
    }

    private String _inputText;

    private final static Object IME_LOCK = new Object();

    public String imeOn(String title, String text, int mode) throws CancelException {
	if (text == null) {
	    throw new NullPointerException("text is null.");
	}
	switch (mode) {
	    case ANY:
		mode = TextField.ANY;
		break;
	    case PASSWORD:
		mode = TextField.PASSWORD;
		break;
	    case NUMBER:
		mode = TextField.NUMERIC;
		break;
	    default:
		throw new IllegalArgumentException("mode is illegal.");
	}
	this.textBox.setTitle(title);
	this.textBox.setString(text);
	this.textBox.setConstraints(mode);

	this._inputText = text;

	// _current = _textBox;
	setNativeCurrent(this.textBox);

	synchronized (IME_LOCK) {
	    while (this.current == this.textBox) {
		try {
		    IME_LOCK.wait();
		} catch (InterruptedException e) {
		}
	    }
	}
	if (this._inputText == null) {
	    throw new CancelException();
	}

	return this._inputText;
    }

    public void setNativeCurrent(Displayable current) {
	if (current == null) {
	    current = this.canvas;
	}
	if (current instanceof Alert) {
	    javax.microedition.lcdui.Display.getDisplay(getMIDlet()).setCurrent(
		    (Alert) current, this.current);
	} else {
	    this.current = current;
	    javax.microedition.lcdui.Display.getDisplay(getMIDlet()).setCurrent(current);
	}
    }

    public int getScreenWidth() {
	return this.canvas.getWidth();
    }

    public int getScreenHeight() {
	return this.canvas.getHeight();
    }

    protected void setMenuItemNavi(MenuItem menuItem) {
	this.canvas.removeCommand(this.menuCmd);
	// _canvas.removeCommand(_spaceMenuCmd);

	if (menuItem != null /* && !isPopupMenuDialogShowing() */) {
	    this.menuCmd = new Command(menuItem.getLabel(), Command.SCREEN, 0);
	    this.canvas.addCommand(this.menuCmd);
	} /*
	   * else { _canvas.addCommand(_spaceMenuCmd); }
	   */
    }

    protected void setPopupMenuItemNavi(MenuItem menuItem) {
	this.canvas.removeCommand(this.popMenuCmd);

	if (menuItem != null /* && !isMenuDialogShowing() */) {
	    this.popMenuCmd = new Command(menuItem.getLabel(), Command.SCREEN, 1);
	    this.canvas.addCommand(this.popMenuCmd);
	}
    }

    protected void paint(int x, int y, int width, int height, boolean direct) {
	this.canvas.g.setClip(0, 0, getScreenWidth(), getScreenHeight());
	this.canvas.g.clipRect(x, y, width, height);
	MIDPDisplay.this.paint(new MIDPGraphics(this.midpFontProvider, this.canvas.g));
	this.canvas.repaint(x, y, width, height);
	if (direct) {
	    this.canvas.serviceRepaints();
	}
    }

    private void commandAction(final Command command, Displayable displayable) {
	if (displayable == this.canvas) {
	    invoke(new Runnable() {
		public void run() {
		    if (command == MIDPDisplay.this.menuCmd) {
			showMenuDialog();
		    } else if (command == MIDPDisplay.this.popMenuCmd) {
			showPopupMenuDialog();
		    }
		}
	    });
	} else if (displayable == this.textBox) {
	    if (command == this.inputOkCmd) {
		this._inputText = this.textBox.getString();
	    } else if (command == this.inputCancelCmd) {
		this._inputText = null;
	    }
	    setNativeCurrent(null);
	    synchronized (IME_LOCK) {
		IME_LOCK.notifyAll();
	    }
	}
    }

    protected int changeMIDPCanvasCodeToKeyEventCode(int keyCode) {
	return KeyEvent.KEY_NON;
    }

    class MWTCanvas extends Canvas {
	private Graphics g;
	private Image image;

	MWTCanvas() {
	    this.image = Image.createImage(getWidth(), getHeight());
	    this.g = this.image.getGraphics();

	    MIDPGraphics.screenWidth = getWidth();
	    MIDPGraphics.screenHeight = getHeight();
	}

	protected void keyPressed(int keyCode) {
	    int code = changeCanvasCodeToKeyEventCode(keyCode);
	    if (code != KeyEvent.KEY_NON) {
		getEventQueue().keyAction(KeyEvent.PRESSED, code);
	    }
	}

	protected void keyRepeated(int keyCode) {
	    int code = changeCanvasCodeToKeyEventCode(keyCode);
	    if (code != KeyEvent.KEY_NON) {
		getEventQueue().keyAction(KeyEvent.REPEATED, code);
	    }
	}

	protected void keyReleased(int keyCode) {
	    int code = changeCanvasCodeToKeyEventCode(keyCode);
	    if (code != KeyEvent.KEY_NON) {
		getEventQueue().keyAction(KeyEvent.RELEASED, code);
	    }
	}

	private int changeCanvasCodeToKeyEventCode(int keyCode) {
	    int c = changeMIDPCanvasCodeToKeyEventCode(keyCode);
	    if (c != KeyEvent.KEY_NON) {
		return c;
	    }
	    switch (keyCode) {
		case KEY_NUM0:
		    return KeyEvent.KEY_NUM0;
		case KEY_NUM1:
		    return KeyEvent.KEY_NUM1;
		case KEY_NUM2:
		    return KeyEvent.KEY_NUM2;
		case KEY_NUM3:
		    return KeyEvent.KEY_NUM3;
		case KEY_NUM4:
		    return KeyEvent.KEY_NUM4;
		case KEY_NUM5:
		    return KeyEvent.KEY_NUM5;
		case KEY_NUM6:
		    return KeyEvent.KEY_NUM6;
		case KEY_NUM7:
		    return KeyEvent.KEY_NUM7;
		case KEY_NUM8:
		    return KeyEvent.KEY_NUM8;
		case KEY_NUM9:
		    return KeyEvent.KEY_NUM9;
		case KEY_POUND:
		    return KeyEvent.KEY_POUND;
		case KEY_STAR:
		    return KeyEvent.KEY_STAR;
	    }
	    int action;
	    try {
		action = getGameAction(keyCode);
	    } catch (Exception e) {
		action = 0;
	    }
	    if (action != 0) {
		switch (action) {
		    case UP:
			return KeyEvent.UP;
		    case DOWN:
			return KeyEvent.DOWN;
		    case LEFT:
			return KeyEvent.LEFT;
		    case RIGHT:
			return KeyEvent.RIGHT;
		    case FIRE:
			return KeyEvent.ENTER;
		}
	    }
	    return KeyEvent.KEY_NON;
	}

	protected void paint(Graphics g) {
	    g.drawImage(this.image, 0, 0, Graphics.TOP | Graphics.LEFT);
	}
    }

    public void destroy() {
    }

    public void initialize() {
	setNativeCurrent(null);
    }

    public void pause() {
    }

    public void start() {
    }
}
